package com.file.parser;

import com.file.bo.AliPay;
import com.file.bo.AliPayTran;
import com.file.bo.ResponseData;
import com.file.constant.ErrorCode;
import com.file.util.JsonUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.pdfbox.pdmodel.PDDocument;
import technology.tabula.*;
import technology.tabula.detectors.NurminenDetectionAlgorithm;
import technology.tabula.extractors.SpreadsheetExtractionAlgorithm;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
public class AlipayPdfParser extends BasePdfParser {

    public ResponseData<String> parseAliPayPdfToJson(String filePath) {
        log.info("parseAliPayPdfToJson started, filePath:{}", filePath);
        String json = null;

        try {
            AliPay alipay = parseAliPayPdf(filePath);
            json = JsonUtils.convertObjectToJson(alipay);
        } catch (Exception e) {
            log.error("[OnError]parseAliPayPdfToJson failed, filePath:{}", filePath, e);
            return new ResponseData<String>(json, ErrorCode.FILE_PARSE_EXCEPTION.getCode(), ErrorCode.FILE_PARSE_EXCEPTION.getMsg());
        }

        log.info("parseAliPayPdfToJson completed, filePath:{}", filePath);
        return new ResponseData<String>(json, ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg());
    }

    public AliPay parseAliPayPdf(String filePath) {
        List<AliPayTran> aliPayTrans = parseTrans(filePath);

        AliPay alipay = parseAliPayHeader(filePath);

        alipay.setAliPayTrans(aliPayTrans);

        return alipay;
    }

    public AliPay parseAliPayHeader(String filePath) {
        AliPay alipay = new AliPay();
        String pdfHeaderText = parsePdfHeaderText(filePath);

        String number = pdfHeaderText.substring(pdfHeaderText.indexOf("编号:") + 3, pdfHeaderText.indexOf("支付宝（中国）网络技术有限公司")).trim();
        String name = pdfHeaderText.substring(pdfHeaderText.indexOf("兹证明") + 4, pdfHeaderText.indexOf("(证件号码")).trim();
        String idNumber = pdfHeaderText.substring(pdfHeaderText.indexOf("证件号码:") + 5, pdfHeaderText.indexOf(")在其支付宝账号")).trim();
        String aliPayAccount = pdfHeaderText.substring(pdfHeaderText.indexOf(")在其支付宝账号") + 8, pdfHeaderText.indexOf("中明细信息如")).trim();
        String currency = pdfHeaderText.substring(pdfHeaderText.indexOf("币种：") + 3, pdfHeaderText.indexOf("/ 单位")).trim();
        String unit = pdfHeaderText.substring(pdfHeaderText.indexOf("单位：") + 3, pdfHeaderText.indexOf("交易时间段：")).trim();
        String transDetailPeriod = pdfHeaderText.substring(pdfHeaderText.indexOf("交易时间段：") + 6, pdfHeaderText.indexOf("交易类型：")).trim();
        String tranType = pdfHeaderText.substring(pdfHeaderText.indexOf("交易类型：") + 5, pdfHeaderText.indexOf("收/支 交易对方")).trim();
        alipay.setNumber(number);
        alipay.setName(name);
        alipay.setIdNumber(idNumber);
        alipay.setCurrency(currency);
        alipay.setUnit(unit);
        alipay.setAliPayAccount(aliPayAccount);
        alipay.setTransDetailPeriod(transDetailPeriod);
        alipay.setTranType(tranType);
        return alipay;
    }

    public List<AliPayTran> parseTrans(String filePath) {
        List<AliPayTran> aliPayTrans = new ArrayList<>();

        // 1. 读取文件
        File pdf = new File(filePath);

        // 2. pdfbox读取PDDocument
        try (PDDocument pdfDocument = PDDocument.load(pdf)) {

            // 3. tabula新建ObjectExtractor和NurminenDetectionAlgorithm，同时准备接收表格Rectangle的结构
            ObjectExtractor objectExtractor = new ObjectExtractor(pdfDocument);
            NurminenDetectionAlgorithm detectionAlgorithm = new NurminenDetectionAlgorithm();
            Map<Integer, List<Rectangle>> detectedTables = new HashMap<>();

            // 4. 获取每页的PageIterator
            PageIterator pages = objectExtractor.extract();

            // 5. 解析每页的Rectangle(table的位置)
            while (pages.hasNext()) {
                Page page = pages.next();
                List<Rectangle> tablesOnPage = detectionAlgorithm.detect(page);
                if (tablesOnPage.size() > 0) {
                    detectedTables.put(Integer.valueOf(page.getPageNumber()), tablesOnPage);
                }
            }

            // 6.通过table位置获取表格具体内容
            SpreadsheetExtractionAlgorithm bea = new SpreadsheetExtractionAlgorithm();

            // 如果单页pdf中有多个表格，则解析出来的List<Rectangle>会有多个对象
            for (Map.Entry<Integer, List<Rectangle>> entry : detectedTables.entrySet()) {
                Page page = objectExtractor.extract(entry.getKey());

                // 支付宝默认每页只有一个表格，因此获取第0个rectangle
                Rectangle rectangle = entry.getValue().get(0);
                Page area = page.getArea(rectangle.getTop(), rectangle.getLeft(), rectangle.getBottom(), rectangle.getRight());

                List<Table> table = bea.extract(area);

                // 支付宝默认每页只有一个表格，因此获取第0个table
                Table t = table.get(0);

                // 判断pdf是否改版，当前版本(20210818)支付宝流水有8列数据
                if (t.getColCount() != 8) {
                    log.error("[OnError]format invalid.");
                    break;
                }

                // 解析第一页时，去掉表头三行数据
                if (entry.getKey() == 1) {
                    for (int i = 0; i < t.getRowCount(); i++) {
                        if (t.getCell(i, 0).getText(false).contains("交易时间段")
                                || t.getCell(i, 0).getText(false).contains("交易类型")
                                || t.getCell(i, 0).getText(false).contains("收/支")) {
                            continue;
                        }
                        AliPayTran aliPayTran = getTransactionByTable(t, i);
                        aliPayTrans.add(aliPayTran);
                    }
                } else {
                    for (int i = 0; i < t.getRowCount(); i++) {
                        AliPayTran aliPayTran = getTransactionByTable(t, i);
                        aliPayTrans.add(aliPayTran);
                    }
                }
            }
        } catch (Exception e) {
            log.error("[OnError]parseTrans failed", e);
            throw new RuntimeException(e);
        }

        return aliPayTrans;
    }

    private AliPayTran getTransactionByTable(Table t, int i) {
        AliPayTran aliPayTran = new AliPayTran();
        aliPayTran.setIncomeOrExpense(t.getCell(i, 0).getText(false));
        aliPayTran.setCounterParty(t.getCell(i, 1).getText(false));
        aliPayTran.setProductDescription(t.getCell(i, 2).getText(false));
        aliPayTran.setPaymentMethod(t.getCell(i, 3).getText(false));
        aliPayTran.setAmt(t.getCell(i, 4).getText(false));
        aliPayTran.setTranOrderNo(t.getCell(i, 5).getText(false));
        aliPayTran.setMerchantOrderNo(t.getCell(i, 6).getText(false));
        aliPayTran.setTranDate(t.getCell(i, 7).getText(false));

        return aliPayTran;
    }

    public static void main(String[] args) {
        AlipayPdfParser alipayPdfParser = new AlipayPdfParser();
        AliPay aliPay = alipayPdfParser.parseAliPayPdf("E:\\data\\file\\alipay\\372746394995265302_842946517a14cd9197db13b513bba9f2_流水证明_202109130008500490284891886386004417582.pdf");
        String json = JsonUtils.convertObjectToJson(aliPay);
        log.info(json);
    }

}
